home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rules / prs2 / prs2plans.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  12.8 KB  |  502 lines

  1. /*===================================================================
  2.  *
  3.  * FILE:
  4.  *   prs2plans.c
  5.  *
  6.  * IDENTIFICATION:
  7.  *   $Header: /private/postgres/src/rules/prs2/RCS/prs2plans.c,v 1.28 1992/07/13 06:10:28 mao Exp $
  8.  *
  9.  * DESCRIPTION:
  10.  *   Various useful routines called by the PRS2 code...
  11.  *
  12.  *
  13.  *===================================================================
  14.  */
  15.  
  16. #include "tmp/postgres.h"
  17. #include "tmp/datum.h"
  18. #include "catalog/syscache.h"
  19. #include "utils/log.h"
  20. #include "nodes/plannodes.h"        /* for EState */
  21. #include "nodes/plannodes.a.h"        /* for EState */
  22. #include "nodes/execnodes.h"        /* for EState */
  23. #include "nodes/execnodes.a.h"        /* for EState */
  24. #include "executor/execdefs.h"
  25. #include "executor/x_execmain.h"
  26. #include "parser/parsetree.h"
  27. #include "utils/fmgr.h"
  28. #include "tcop/dest.h"
  29.  
  30. #include "catalog/pg_prs2rule.h"
  31. #include "catalog/pg_prs2plans.h"
  32.  
  33. extern EState CreateExecutorState();
  34. RuleLock prs2SLOWGetLocksFromRelation();
  35.  
  36. /*-------------------------------------------------------------------
  37.  * prs2GetRulePlanFromCatalog
  38.  * Given a rule id and a plan number get the appropriate plan
  39.  * from the system catalogs. At the same time construct a list
  40.  * with all the Param nodes contained in this plan.
  41.  */
  42. LispValue
  43. prs2GetRulePlanFromCatalog(ruleId, planNumber, paramListP)
  44. ObjectId ruleId;
  45. Prs2PlanNumber planNumber;
  46. ParamListInfo *paramListP;
  47. {
  48.     
  49.  
  50.     HeapTuple planTuple;
  51.     struct prs2plans *planStruct;
  52.     char *planString;
  53.     LispValue plan;
  54.     char *getstruct();
  55.     char *t;
  56.  
  57.     /*
  58.      * get the tuple form the system cache
  59.      */
  60.     planTuple = SearchSysCacheTuple(PRS2PLANCODE, ruleId, planNumber);
  61.     if (planTuple == NULL) {
  62.     /*
  63.      * No such rule exist! Complain!
  64.      */
  65.     elog(WARN,
  66.     "prs2GetRulePlanFromCatalog: plan NOT found (rulid=%ld,planno=%d)\n",
  67.     ruleId, planNumber);
  68.     return(LispNil);
  69.     }
  70.  
  71.     /*
  72.      * given the tuple extract the 'struct prs2plans' structure
  73.      */
  74.     planStruct = (struct prs2plans *) GETSTRUCT(planTuple);
  75.  
  76.     /*
  77.      * This is a little bit tricky but it works!
  78.      *
  79.      * t = VARDATA(&planStruct->prs2code);
  80.      * planString = PSIZESKIP(t);
  81.      *
  82.      * Unfortunately it assumes the wrong semantics, and this
  83.      * causes problems when things change.
  84.      */
  85.      planString = VARDATA(&(planStruct->prs2code));
  86.  
  87.     if (paramListP == NULL)
  88.     plan = StringToPlan(planString);
  89.     else
  90.     plan = StringToPlanWithParams(planString, paramListP);
  91.  
  92.     return(plan);
  93. }
  94.  
  95. /*------------------------------------------------------------------
  96.  *
  97.  * prs2GetLocksFromRelation
  98.  *
  99.  * Given a relation, find all its relation level locks.
  100.  * We have to go to the RelationRelation, get the tuple that corresponds
  101.  * to the given relation and extract its locks field.
  102.  *
  103.  * NOTE: we are returning a pointer to a *copy* of the locks!
  104.  */
  105. RuleLock
  106. prs2GetLocksFromRelation(relationName)
  107. Name relationName;
  108. {
  109.     HeapTuple relationTuple;
  110.     RuleLock relationLocks;
  111.  
  112.     /*
  113.      * Search the system cache for the relation tuple
  114.      */
  115.     relationTuple = SearchSysCacheTuple(RELNAME,
  116.                 relationName,
  117.                 (char *) NULL,
  118.                 (char *) NULL,
  119.                 (char *) NULL);
  120.     if (!HeapTupleIsValid(relationTuple)) {
  121.     elog(WARN, "prs2GetLocksFromRelation: no rel with name '%s'\n",
  122.     relationName);
  123.     }
  124.  
  125.     relationLocks = prs2GetLocksFromTuple(relationTuple, InvalidBuffer);
  126.  
  127.     return(relationLocks);
  128. }
  129.  
  130. /*------------------------------------------------------------------
  131.  * prs2SLOWGetLocksFromRelation
  132.  *
  133.  * get the locks but without using the sys cache.
  134.  * Do a scan in the pg_class...
  135.  * The only reason for the existence of this routine was a flaky system
  136.  * cache... I kust keep it here in case things are broken again.
  137.  *
  138.  *------------------------------------------------------------------
  139.  */
  140. RuleLock
  141. prs2SLOWGetLocksFromRelation(relationName)
  142. Name relationName;
  143. {
  144.     Relation rel;
  145.     TupleDescriptor tdesc;
  146.     ScanKeyData scanKey;
  147.     HeapScanDesc scanDesc;
  148.     HeapTuple tuple;
  149.     Buffer buffer;
  150.     RuleLock locks;
  151.  
  152.     rel = RelationNameOpenHeapRelation(Name_pg_relation);
  153.     tdesc = RelationGetTupleDescriptor(rel);
  154.     /*----
  155.      * Scan pg_relation
  156.      */
  157.     ScanKeyEntryInitialize(&scanKey.data[0], 0, Anum_pg_relation_relname,
  158.                            F_CHAR16EQ, NameGetDatum(relationName));
  159.     scanDesc = RelationBeginHeapScan(rel, false, NowTimeQual, 1, &scanKey);
  160.     tuple = HeapScanGetNextTuple(scanDesc, false, &buffer);
  161.     locks = prs2GetLocksFromTuple(tuple, buffer);
  162.     RelationCloseHeapRelation(rel);
  163.     HeapScanEnd(scanDesc);
  164.  
  165.     return(locks);
  166. }
  167. /*------------------------------------------------------------------
  168.  *
  169.  * prs2CheckQual
  170.  *
  171.  * Return 1 if the given rule qualification is true
  172.  * (i.e. it returns at least one tuple).
  173.  * Otherwise return 0.
  174.  *
  175.  * NOTE: A null qualification always evaluates to true.
  176.  *
  177.  */
  178. int
  179. prs2CheckQual(planQual, paramList, prs2EStateInfo)
  180. LispValue planQual;
  181. ParamListInfo paramList;
  182. Prs2EStateInfo prs2EStateInfo;
  183. {
  184.     int status;
  185.  
  186.     if (planQual == LispNil)
  187.     return(1);
  188.  
  189.     status = prs2RunOnePlanAndGetValue(
  190.             planQual,
  191.             paramList,
  192.             prs2EStateInfo,
  193.             NULL, NULL, NULL);
  194.     
  195.     return(status);
  196. }
  197.  
  198. /*------------------------------------------------------------------
  199.  *
  200.  * prs2RunActionPlans
  201.  *
  202.  */
  203.  
  204. void
  205. prs2RunActionPlans(plans, paramList, prs2EStateInfo)
  206. LispValue plans;
  207. ParamListInfo paramList;
  208. Prs2EStateInfo prs2EStateInfo;
  209. {
  210.     int feature;
  211.     LispValue onePlan;
  212.  
  213.     foreach(onePlan, plans) {
  214.     /*
  215.      * XXX SOS XXX
  216.      * What kind of 'feature' should we use ??
  217.      */
  218.     feature = EXEC_RUN;
  219.     prs2RunOnePlan(CAR(onePlan), paramList, prs2EStateInfo, feature);
  220.     }
  221.     
  222. }
  223.  
  224. /*------------------------------------------------------------------
  225.  *
  226.  * prs2RunOnePlanAndGetValue
  227.  *
  228.  * Run a retrieve plan and return 1 if a tuple was found or 0 if there
  229.  * was no tuple.
  230.  * 
  231.  * Sometimes when we call this routine, we are only interested in
  232.  * whether there is a tuple returned or not, but we are *not*
  233.  * interested in the tuple itself (for instance, when we test
  234.  * a rule qualification).
  235.  * In this case, "valueP" and "isNullP" are NULL
  236.  *
  237.  * On the other hand, sometimes (when we execute the action part of an 
  238.  * "on retrieve ... do instead retrieve ..." rule) we want the value of
  239.  * the tuple's attribute too. This tuple has always one attribute.
  240.  * NOTE: We make a copy of the attribute!
  241.  * 
  242.  */
  243.  
  244. int
  245. prs2RunOnePlanAndGetValue(actionPlan, paramList, prs2EStateInfo,
  246.                 valueP, isNullP)
  247. LispValue actionPlan;
  248. ParamListInfo paramList;
  249. Prs2EStateInfo prs2EStateInfo;
  250. Datum *valueP;
  251. Boolean *isNullP;
  252. {
  253.     
  254.     AttributeNumber numberOfAttributes;
  255.     TupleDescriptor resultTupleDescriptor;
  256.     LispValue queryDescriptor;
  257.     LispValue res1, res2, res3;
  258.     EState executorState;
  259.     HeapTuple resultTuple;
  260.     TupleTableSlot slot;
  261.     bool oldPolicy;
  262.     int status;
  263.  
  264.     queryDescriptor = prs2MakeQueryDescriptorFromPlan(actionPlan);
  265.  
  266.     executorState = CreateExecutorState();
  267.     set_es_param_list_info(executorState, paramList);
  268.     set_es_prs2_info(executorState, prs2EStateInfo);
  269.  
  270.     res1 = ExecMain(queryDescriptor, executorState,
  271.             lispCons(lispInteger(EXEC_START), LispNil));
  272.  
  273.  
  274.     /*
  275.      * When the executor is called with EXEC_START it returns
  276.      * "lispCons(LispInteger(n), lispCons(t, lispNil))"
  277.      * where 'n' is the number of attributes in the result tuple
  278.      * and 't' is an 'AttributePtr'.
  279.      * XXX Note: it appears that 'AttributePtr' and 'TupleDescriptor'
  280.      * are the same thing!
  281.      */
  282.  
  283.     /*
  284.      * XXX - 
  285.      * Unfortunately, by now the executor has freed (with pfree) the tuple
  286.      * descriptor!!!  You will have to either copy it or work out something
  287.      * with Cim - I hacked the executor to avoid freeing this for now,
  288.      * but it *should* be freeing these things to prevent memory leaks.
  289.      *
  290.      * -- Greg
  291.      */
  292.     numberOfAttributes = (AttributeNumber) CInteger(CAR(res1));
  293.     resultTupleDescriptor = (TupleDescriptor) CADR(res1);
  294.  
  295.  
  296.     /*
  297.      * now retrieve one tuple
  298.      */
  299.     res2 = ExecMain(queryDescriptor, executorState,
  300.             lispCons(lispInteger(EXEC_RETONE), LispNil));
  301.     /*
  302.      * "res2" is a 'TupleTableSlot', containing a tuple that will
  303.      * might be freed by the next call to the executor (with operation
  304.      * EXEC_END). However, we might want to use the values of this
  305.      * tuple, in which case we must not free it.
  306.      * To do that, we copy the given slot to another one
  307.      * and change the "freeing policy" of the original slot
  308.      * to "false"
  309.      */
  310.     slot = (TupleTableSlot) res2;
  311.     resultTuple = (HeapTuple) ExecFetchTuple(slot);
  312.     if (resultTuple == NULL) { 
  313.     /*
  314.      * No tuple was returned...
  315.      * XXX What shall we do??
  316.      * Options:
  317.      *    1) bomb!
  318.      *    2) continue with the next rule
  319.      *    3) assume a nil value
  320.      * Currently option (2) is implemented.
  321.      */
  322.     status = 0;    /* this means no value found */
  323.     } else {
  324.     /*
  325.      * A tuple was found. Find the value of its attribute.
  326.      * NOTE: for the time being we assume that this tuple
  327.      * has only one attribute!
  328.      */
  329.     Datum val;
  330.  
  331.     if (valueP != NULL && isNullP != NULL) {
  332.         val = HeapTupleGetAttributeValue(
  333.             resultTuple,
  334.             InvalidBuffer,
  335.             (AttributeNumber) 1,
  336.             resultTupleDescriptor,
  337.             isNullP);
  338.         *valueP = datumCopy(val,
  339.             resultTupleDescriptor->data[0]->atttypid,
  340.             resultTupleDescriptor->data[0]->attbyval,
  341.             (Size) resultTupleDescriptor->data[0]->attlen);
  342.  
  343.     }
  344.     status = 1;
  345.     }
  346.  
  347.     /*
  348.      * let the executor do the cleaning up...
  349.      */
  350.     res3 = ExecMain(queryDescriptor, executorState,
  351.             lispCons(lispInteger(EXEC_END), LispNil));
  352.     
  353.     return(status);
  354. }
  355.  
  356. /*------------------------------------------------------------------
  357.  *
  358.  * prs2RunOnePlan
  359.  *
  360.  * Run one plan. Ignore the return values from the executor.
  361.  *
  362.  */
  363.  
  364. void
  365. prs2RunOnePlan(actionPlan, paramList, prs2EStateInfo, operation)
  366. LispValue actionPlan;
  367. ParamListInfo paramList;
  368. Prs2EStateInfo prs2EStateInfo;
  369. int operation;
  370. {
  371.     LispValue queryDescriptor;
  372.     LispValue res1, res2, res3;
  373.     EState executorState;
  374.     TupleDescriptor foo; /* XXX Hack for making copy of tuple descriptor */
  375.  
  376.     queryDescriptor = prs2MakeQueryDescriptorFromPlan(actionPlan);
  377.  
  378.     executorState = CreateExecutorState();
  379.     set_es_param_list_info(executorState, paramList);
  380.     set_es_prs2_info(executorState, prs2EStateInfo);
  381.  
  382.     res1 = ExecMain(queryDescriptor, executorState,
  383.             lispCons(lispInteger(EXEC_START), LispNil));
  384.  
  385.     res2 = ExecMain(queryDescriptor, executorState,
  386.             lispCons(lispInteger(operation), LispNil));
  387.     res3 = ExecMain(queryDescriptor, executorState,
  388.             lispCons(lispInteger(EXEC_END), LispNil));
  389. }
  390.  
  391. /*------------------------------------------------------------------
  392.  *
  393.  * prs2IsRuleInsteadFromRuleInfo
  394.  *
  395.  * Given the 'rule info' stored in pg_prs2plans return true iff
  396.  * a rule is an 'instead' rule, otherwise return false
  397.  */
  398. Boolean
  399. prs2IsRuleInsteadFromRuleInfo(ruleInfo)
  400. LispValue ruleInfo;
  401. {
  402.     LispValue t;
  403.     char *s;
  404.  
  405.     t = CAR(ruleInfo);
  406.     s = CString(t);
  407.  
  408.     if (!strcmp("instead", s)) {
  409.     return((Boolean) 1);
  410.     } else {
  411.     return((Boolean) 0);
  412.     }
  413. }
  414.  
  415. /*------------------------------------------------------------------
  416.  *
  417.  * prs2GetEventAttributeNumberFromRuleInfo
  418.  *
  419.  * Given the 'rule info' as stored in pg_prs2plans, 
  420.  * return the attribute number of the attribute specified in the
  421.  * 'ON EVENT to REL.attr' clause
  422.  */
  423. AttributeNumber
  424. prs2GetEventAttributeNumberFromRuleInfo(ruleInfo)
  425. LispValue ruleInfo;
  426. {
  427.     LispValue t;
  428.     int n;
  429.  
  430.     t = CAR(CDR(ruleInfo));
  431.     n = CInteger(t);
  432.  
  433.     return(n);
  434. }
  435.  
  436.  
  437. /*------------------------------------------------------------------
  438.  *
  439.  * prs2GetUpdatedAttributeNumberFromRuleInfo
  440.  *
  441.  * Given the 'rule info' as stored in pg_prs2plans, 
  442.  * return the attribute number of the attribute of the CURRENT tuple
  443.  * which is updated by the rule. This only applies to rules of the
  444.  * form 'ON RETRIEVE TO REL.X DO RETRIEVE INSTEAD (X = ...)' or
  445.  * 'ON REPLACE TO REL.Y DO REPLACE CURRENT(X = ....)'.
  446.  */
  447. AttributeNumber
  448. prs2GetUpdatedAttributeNumberFromRuleInfo(ruleInfo)
  449. LispValue ruleInfo;
  450. {
  451.     LispValue t;
  452.     int n;
  453.  
  454.     t = CAR(CDR(CDR(ruleInfo)));
  455.     n = CInteger(t);
  456.  
  457.     return(n);
  458. }
  459.  
  460.  
  461. /*------------------------------------------------------------------
  462.  *
  463.  * prs2MakeQueryDescriptorFromPlan
  464.  *
  465.  * Given the actionPlan, the paramList and the prs2EStateInfo,
  466.  * create a query descriptor
  467.  */
  468.  
  469. LispValue
  470. prs2MakeQueryDescriptorFromPlan(actionPlan)
  471. LispValue actionPlan;
  472. {
  473.     LispValue queryDescriptor;
  474.     LispValue parseTree;
  475.     LispValue plan;
  476.     LispValue command;
  477.  
  478.  
  479.     /*
  480.      * the actionPlan must be a list containing the parsetree & the
  481.      * plan that has to be executed.
  482.      */
  483.     parseTree = prs2GetParseTreeFromOneActionPlan(actionPlan);
  484.     plan = prs2GetPlanFromOneActionPlan(actionPlan);
  485.  
  486.     command = root_command_type_atom(parse_root(parseTree));
  487.  
  488.     queryDescriptor = (LispValue)
  489.             MakeQueryDesc(
  490.                 command,
  491.                 parseTree,
  492.                 plan,
  493.                 LispNil,
  494.                 LispNil,
  495.                 LispNil,
  496.                 LispNil,
  497.                 lispInteger(0),
  498.                 None);
  499.  
  500.     return(queryDescriptor);
  501. }
  502.